package utils

import (
	"errors"
	"reflect"
)

func IsSlice(item any) bool {
	return reflect.TypeOf(item).Kind() == reflect.Slice
}

// 从slice 中查找field 的值，支持struct ,map
func FieldsFromSlice(items interface{}, fieldName string) []any {
	val := reflect.ValueOf(items)
	if val.Kind() != reflect.Slice {
		return nil
	}
	ret := make([]any, 0, val.Len())
	for i := 0; i < val.Len(); i++ {
		item := val.Index(i).Interface()
		itemType := reflect.TypeOf(item)

		if TypeRealKind(itemType) == reflect.Map {
			ret = append(ret, item.(map[string]any)[fieldName])
		} else if TypeRealKind(itemType) == reflect.Struct {
			ret = append(ret, GetRealValue(item).FieldByName(fieldName).Interface())
		} else {
			ret = append(ret, item)
		}
	}
	return ret
}

// slice1, slice2是map,或struct类型，根据key进行比较，返回slice1中key不存在于slice2中的元素，以及slice2中key不存在于slice1中的元素
func DiffSliceByKey[T any](srcSlice, destSlice []T, key string) (addItems []T, delItems []T, err error) {
	// 获取 slice1 中的 key 映射
	map1 := make(map[any]T)
	for _, item := range srcSlice {
		val, err := getField(item, key)
		if err != nil {
			return nil, nil, err
		}
		map1[val] = item
	}

	// 获取 slice2 中的 key 映射
	map2 := make(map[any]T)
	for _, item := range destSlice {
		val, err := getField(item, key)
		if err != nil {
			return nil, nil, err
		}
		map2[val] = item
	}

	// 找出 slice1 中存在但在 slice2 中不存在的元素
	for key, item := range map1 {
		if _, exists := map2[key]; !exists {
			delItems = append(delItems, item)
		}
	}

	// 找出 slice2 中存在但在 slice1 中不存在的元素
	for key, item := range map2 {
		if _, exists := map1[key]; !exists {
			addItems = append(addItems, item)
		}
	}

	return addItems, delItems, nil
}

func RestoreAnyTypeSlice[T any](ary []any) []T {
	ret := make([]T, 0)
	for _, item := range ary {
		ret = append(ret, item.(T))
	}
	return ret
}

func IsSliceNilOrEmpty(slice interface{}) bool {
	if slice == nil {
		return true
	}
	val := reflect.ValueOf(slice)
	return val.Kind() == reflect.Slice && val.Len() == 0
}

// SliceAppendIfNotExist 函数将字符串str添加到切片s中，如果str已经存在于s中则不进行任何操作。
// 参数s为需要添加字符串的切片，参数str为需要添加的字符串。
// 返回值为添加后的切片s。
func SliceAppendIfNotExist(slice []string, str string) []string {
	for _, v := range slice {
		if str == v {
			return slice
		}
	}
	return append(slice, str)
}

// SliceFindIndex 在字符串切片中查找指定字符串的索引位置
// 参数slice为待查找的字符串切片
// 参数str为待查找的字符串
// 返回值为找到的索引位置，若未找到则返回-1
func SliceFindIndex(slice []string, str string) int {
	for i, v := range slice {
		if str == v {
			return i
		}
	}
	return -1
}

// SliceRemoveValue 从字符串切片中删除指定值，并返回新的切片
// 参数：
// slice：待操作的字符串切片
// value：待删除的值
// 返回值：
// 删除指定值后的新切片
func SliceRemoveValue(slice []string, value string) []string {
	var result []string
	for _, v := range slice {
		if v != value {
			result = append(result, v)
		}
	}
	return result
}

// RemoveDuplicatesFromSlice 函数接收一个字符串数组 arr 作为参数，
// 返回一个新的字符串数组，该数组不包含 arr 中的重复元素。
func RemoveDuplicatesFromSlice(arr []string) []string {
	uniqueValues := make(map[string]struct{})
	var result []string
	for _, value := range arr {
		if _, ok := uniqueValues[value]; !ok {
			uniqueValues[value] = struct{}{}
			result = append(result, value)
		}
	}
	return result
}

// getField 获取结构体或映射中的字段值
func getField(item any, fieldName string) (any, error) {
	val := reflect.ValueOf(item)
	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}

	switch val.Kind() {
	case reflect.Struct:
		field := val.FieldByName(fieldName)
		if !field.IsValid() {
			return nil, errors.New("field not found in struct")
		}
		return field.Interface(), nil
	case reflect.Map:
		if val.Type().Key().Kind() != reflect.String {
			return nil, errors.New("map key must be string")
		}
		result := val.MapIndex(reflect.ValueOf(fieldName))
		if !result.IsValid() {
			return nil, errors.New("field not found in map")
		}
		return result.Interface(), nil
	default:
		return nil, errors.New("item must be a struct or map")
	}
}
